package com.hansen.library.ui.widget.ratingbar;

import android.content.Context;
import android.content.res.TypedArray;
import android.support.annotation.Nullable;
import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;

import com.hansen.library.R;
import com.hansen.library.utils.ScreenSizeUtils;
import com.hansen.library.utils.StringUtils;

import java.math.BigDecimal;

/**
 * 自定义 rating bar
 * Created by han on 2018/10/29 0029.
 */

public class CustomRatingBar extends LinearLayout {

    private Context mContext;

    private View mRootView;
    /**
     * 是否可点击
     */
    private boolean mClickable;
    /**
     * 星星数量
     */
    private int mStarCount;
    /**
     * 每个星星的大小
     */
    private int mStarImageSize;
    /**
     * 每个星星的间距
     */
    private int mStarPadding;
    /**
     * 星星的显示数量，支持小数点
     */
    private float mSelectStarValue;
    /**
     * 空白的默认星星图片
     */
    private int mStarEmptyResId;
    /**
     * 选中后的星星填充图片
     */
    private int mStarFillResId;
    /**
     * 半颗星的图片
     */
    private int mStarHalfResId;
    /**
     * 每次点击星星所增加的量是整个还是半个
     */
    private StepSize mStepSize;
    private int dp10;

    private OnRatingChangeListener onRatingChangeListener;

    public CustomRatingBar(Context context) {
        this(context, null);
    }

    public CustomRatingBar(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CustomRatingBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        mContext = context;

        setOrientation(HORIZONTAL);

        dp10 = ScreenSizeUtils.dp2px(mContext, 10);

        TypedArray array = mContext.obtainStyledAttributes(attrs, R.styleable.CustomRatingBarStyles);

        mStarImageSize = array.getDimensionPixelSize(R.styleable.CustomRatingBarStyles_starImageSize, 0);
        mStarPadding = array.getDimensionPixelSize(R.styleable.CustomRatingBarStyles_starPadding, 3);
        mSelectStarValue = array.getFloat(R.styleable.CustomRatingBarStyles_selectStartValue, 0f);
        mStepSize = StepSize.fromStep(array.getInt(R.styleable.CustomRatingBarStyles_stepSize, 1));
        mStarCount = array.getInteger(R.styleable.CustomRatingBarStyles_starsTotalCount, 5);
        mStarEmptyResId = array.getResourceId(R.styleable.CustomRatingBarStyles_starEmpty, R.mipmap.icon_star_yellow_gray);
        mStarFillResId = array.getResourceId(R.styleable.CustomRatingBarStyles_starFill, R.mipmap.icon_star_yellow_full);
        mStarHalfResId = array.getResourceId(R.styleable.CustomRatingBarStyles_starHalf, R.mipmap.icon_star_yellow_half);
        mClickable = array.getBoolean(R.styleable.CustomRatingBarStyles_starClickable, false);

        array.recycle();

        AppCompatImageView imageView;

        for (int i = 0; i < mStarCount; i++) {
            imageView = getStarImageView(new AppCompatImageView(mContext));

            addView(imageView);
        }

        setStar(mSelectStarValue);
    }

    /**
     * 设置每颗星星的参数
     *
     * @return
     */
    private AppCompatImageView getStarImageView(AppCompatImageView imageView) {
        if(imageView == null) {
            imageView = new AppCompatImageView(mContext);
        }

        if(mStarImageSize <= 0) {
            mStarImageSize = LayoutParams.WRAP_CONTENT;
        }

        LayoutParams layout = new LayoutParams(mStarImageSize, mStarImageSize);//设置每颗星星在线性布局的大小
        layout.setMargins(mStarPadding, 0, mStarPadding, 0);//设置每颗星星在线性布局的间距

        imageView.setLayoutParams(layout);
        imageView.setAdjustViewBounds(true);
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        imageView.setImageResource(mStarEmptyResId);
        imageView.setMinimumWidth(dp10);
        imageView.setMinimumHeight(dp10);

        return imageView;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mRootView = getRootView();

        if (mRootView == null || !(mRootView instanceof ViewGroup)) {
            return false;
        }

        if(!mClickable) {
            return super.onTouchEvent(event);
        }

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
                setStar(caculateStarsValue(event.getX()));
                break;
            default:
                break;
        }

        return true;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        if(mStarImageSize <= 0) {// 防止 imageview宽高设置match_parent和wrap_content后导致mStarImageSize小于0
            mStarImageSize = (w - mStarPadding) / mStarCount;
        }
    }

    /**
     * 根据当前点击,或者滑动的位置，计算所需要显示的星星的个数
     *
     * @param x 传入当前点击或滑动位置（单位像素，不是dp），
     *          返回值 返回0.5的倍数，返回多少个星星，比如3.5个星星，就是第3个和第4个星星中间被点击
     */
    private float caculateStarsValue(float x) {
        float fResult = 0.0f;
        float oneStarWidth = mStarImageSize + mStarPadding * 2;
        float value = x * 2 / oneStarWidth;

        fResult = ((float) Math.round(value) / 2) + 0.5f;
        //LogUtils.e("iOneStarWidth = " + oneStarWidth + ",  fResult = " + fResult + ", value = " + value + ",   x=" + x);

        return fResult;
    }

    public void setStar(String rating) {
        if(!StringUtils.isNumber(rating)) {
            setStar(0f);
            return;
        }

        setStar(Float.parseFloat(rating));
    }

    /**
     * 设置星星的个数
     *
     * @param rating 传入的值，是0.5的整数倍，比如共5个星，显示3.5个星
     */
    public void setStar(float rating) {
        //LogUtils.e("mSelectStarValue===" + mSelectStarValue + "rating====" + rating);
        if (mSelectStarValue == rating) {
            return;
        }

        if (rating >= mStarCount) {
            rating = mStarCount;
        }

        if (rating <= 0) {
            rating = 0;
        }

        // 浮点数的整数部分
        int fint = (int) rating;

        BigDecimal b1 = new BigDecimal(Float.toString(rating));
        BigDecimal b2 = new BigDecimal(Integer.toString(fint));

        // 浮点数的小数部分
        float fPoint = b1.subtract(b2).floatValue();

        if(mStepSize == StepSize.Full) {
            if(fPoint > 0) {
                fPoint = 0;
                fint += 1;
                rating = fint;
            }
        }

        if (onRatingChangeListener != null) {
            onRatingChangeListener.onRatingChange(this, rating);
        }

        this.mSelectStarValue = rating;

        // 设置选中的星星
        for (int i = 0; i < fint; ++i) {
            ((AppCompatImageView) getChildAt(i)).setImageResource(mStarFillResId);
        }

        // 设置没有选中的星星
        for (int i = fint; i < mStarCount; i++) {
            ((AppCompatImageView) getChildAt(i)).setImageResource(mStarEmptyResId);
        }

        // 小数点默认增加半颗星
        if (fPoint > 0) {
            ((AppCompatImageView) getChildAt(fint)).setImageResource(mStarHalfResId);
        }
    }

    public boolean isClickable() {
        return mClickable;
    }

    public void setClickable(boolean mClickable) {
        this.mClickable = mClickable;
    }

    public void setOnRatingChangeListener(OnRatingChangeListener onRatingChangeListener) {
        this.onRatingChangeListener = onRatingChangeListener;
    }

    /**
     * 星星每次增加的方式整星还是半星，枚举类型
     * 类似于View.GONE
     */
    public enum StepSize {
        Half(0), Full(1);
        int step;

        StepSize(int step) {
            this.step = step;
        }

        public static StepSize fromStep(int step) {
            for (StepSize f : values()) {
                if (f.step == step) {
                    return f;
                }
            }
            throw new IllegalArgumentException();
        }
    }

    /**
     * 操作星星的点击事件
     */
    public interface OnRatingChangeListener {
        /**
         * 选中的星星的个数
         *
         * @param ratingCount
         */
        void onRatingChange(CustomRatingBar ratingBar, float ratingCount);

    }
}
